﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Runtime.Caching;
using System.Text;
using nanoCMS.Core.Concrete;
using nanoCMS.Core.Providers;

namespace nanoCMS.Core.Membership
{
	public class UserRoleProvider
	{
		private readonly Entities entities;
		private readonly CacheProvider cacheProvider;

		public UserRoleProvider(Entities entities)
		{
			this.entities = entities;
			this.cacheProvider = CacheProvider.Default;
		}

		public bool IsUserRoot(int userID)
		{
			var rootUser = Convert.ToInt32(ConfigurationManager.AppSettings.Get("RootUserID"));
			return rootUser == userID;
		}


		public bool IsUserInRole(int userID, int roleID, int tenantID = 1)
		{
			return entities.UserInRoles.Any(x => x.UserID == userID && x.RoleID == roleID && x.TenantID == tenantID);
		}

		public bool IsUserInRole(int userID, string roleName, int tenantID = 1)
		{
			int roleID = GetRoleID(roleName);
			return IsUserInRole(userID, roleID, tenantID);
		}

		public bool IsUserInRole(int userID, List<int> roles, int tenanatID = 1 )
		{
			return roles.Any(role => IsUserInRole(userID, role, tenanatID));
		}


		public bool IsUserInRole(int userID, string[] roles, int tenantID = 1)
		{
			return roles.Any(role => IsUserInRole(userID, role, tenantID));
		}


		public bool AddUserToRole(int userID, int roleID, int tenantID = 1, string comment = "")
		{
			if (IsUserInRole(userID, roleID, tenantID)) return false;
		   
			UserInRole userInRole = new UserInRole
									{
										UserID = userID, 
										RoleID = roleID,
										TenantID = tenantID,
										Comment = comment
									};
			entities.UserInRoles.AddObject(userInRole);
			entities.SaveChanges();
			return true;
		}

		public List<UserInRole> GetUserRoles(int userID)
		{
			return entities.UserInRoles.Where(x => x.UserID == userID).ToList();
		}

		public bool RemoveUserFromRole(int userID, int roleID, int tenantID = 1)
		{
			var userInRole =
				entities.UserInRoles.SingleOrDefault(
					x => x.UserID == userID && x.RoleID == roleID && x.TenantID == tenantID);
			if (userInRole == null) return false;
			entities.UserInRoles.DeleteObject(userInRole);
			entities.SaveChanges();
			return true;
		}

		public List<UserRole> GetAllRoles()
		{
			const string cacheKey = "UserRoles";
			if (cacheProvider.Contains(cacheKey))
				return cacheProvider.Get(cacheKey) as List<UserRole>;

			List<UserRole> userRoles = entities.UserRoles.ToList();
			cacheProvider.Add(cacheKey, userRoles, new CacheItemPolicy { SlidingExpiration = new TimeSpan(0, 1, 0, 0) });
			return userRoles;
		}

		public string GetRoleName(int roleID)
		{
			List<UserRole> roles = GetAllRoles();
			var singleOrDefault = roles.SingleOrDefault(x => x.RoleID == roleID);
			if (singleOrDefault == null) throw new ArgumentOutOfRangeException("Role with ID=" + roleID + ", doesn't exist");
				return singleOrDefault.Name;
		}

		public int GetRoleID(string roleName)
		{
			List<UserRole> roles = GetAllRoles();
			var singleOrDefault = roles.SingleOrDefault(x => x.Name == roleName);
			if (singleOrDefault == null) throw new ArgumentException("Role with name=" + roleName + ", doesn't exist");
			return singleOrDefault.RoleID;
		}

		
	}
}
